import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author David Beaver
 */
public class ExecServer {
    private ServerSocket serverManager;
    private FtpServer ftpManager;
    private ServerConfig config;
    private ThreadPool pool;
    
    public ExecServer(String configFile){
        try{
            this.config = new ServerConfig();
            System.out.println("*************************************");
            System.out.println("WICE Remote Execution Server");
            System.out.println("Authors: David Beaver & Omkar Dangkat");
            System.out.println("*************************************");
            System.out.println("Configuring Server...");
            System.out.print("\t[1]Loading "+configFile+"...");
            this.config.loadConfig(configFile);
            System.out.println("OK\n"+this.config.printConfig());
            this.serverManager = new ServerSocket(this.config.getPort());
            this.ftpManager = new FtpServer(this.config.getFtpPort(),this.config);
            pool = new ThreadPool((int)this.config.getMaxThreads()/2);
        }catch(IOException ex){
            System.out.println("EXEC: Error creating socket");
        }
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        String configFile;
        if (args.length > 0) {
           configFile = args[0];
           ExecServer myServer = new ExecServer(configFile);
            myServer.startFtpServer();
            System.out.println("EXEC: Listening for commands...");
            while(true){
                myServer.processRequests();
            }
        }else{
            System.out.println("A configuration file must be given on the command line");
        }
        
    }
    public void startFtpServer(){
        new Thread(this.ftpManager).start();
    }
    
    public void processRequests(){
        try{
            RequestThread requestHandler = new RequestThread(serverManager.accept(), this.config);
            System.out.println("\nEXEC: Incoming command!!");
            this.pool.assign(new Thread(requestHandler));
        } catch(IOException ex) {
            System.out.println("\nEXEC: Error receving Server Manager request");
        }
    }

    class RequestThread implements Runnable {
        private Socket incoming;
        private BufferedReader input;
        private BufferedOutputStream output;
        private Request request;
        private Response response;
        
        public RequestThread(Socket incoming, ServerConfig config){
            try {
                this.incoming = incoming;
                this.input = new BufferedReader(new InputStreamReader(this.incoming.getInputStream()));
                this.output = new BufferedOutputStream(this.incoming.getOutputStream());
                this.request = new Request();
                this.response = new Response(config);
            } catch (IOException ex) {
                Logger.getLogger(ExecServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        @Override
        public void run(){
            try {
                this.request.processRequest(this.input);
                this.response.processRequest(this.request);
                this.response.sendResponse(this.output);
                this.output.flush();
                if(!this.incoming.isClosed()){
                    this.incoming.close();
                }
            }catch (IOException ex) {
                System.out.println("EXEC: Communication failed");
            }
        }
    }
}
